﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GrandwayLib.Meters.Interfaces;
using System.IO.Ports;
using System.Threading;

namespace GrandwayLib.Meters.Classes
{
    /// <summary>
    /// 张国宝提供的衰减器,上海文简WG3020
    /// </summary>
    public class ATT_WG3020 : IAttenuation
    {
        private bool isConnected = false; //是否已连接
        private SerialPortParam serialPortParam = new SerialPortParam(SerialPort.GetPortNames().Count() > 0 ? SerialPort.GetPortNames()[0] : "COM1", 19200); //串口参数,默认值为第一个可用端口，如果没有时，使用"COM1"
        private SerialPort serialPort = null; //串口对象
        private AutoResetEvent getMeterTypeEvent = new AutoResetEvent(false); //获取设备名称成功信号量
        private AutoResetEvent dataReceiveEvent = new AutoResetEvent(false); //数据到达信号量
        private AutoResetEvent waveChangedEvent = new AutoResetEvent(false); //切换波长成功信号量
        private AutoResetEvent setAttenEvent = new AutoResetEvent(false); //调节衰减值成功信号量
        private AutoResetEvent getAttenValueEvent = new AutoResetEvent(false); //读取衰减值成功信号量
        private List<byte> receiveByteList = null; //收到的数据清单
        private int[] wavelengthArr = { 1270, 1310, 1490, 1550, 1577, 1625, 1650 }; //该机型只能切换到这些波长
        private System.Timers.Timer checkConnectionTimer = new System.Timers.Timer(1000); //设置一个1秒的定时器，定制查看连接是否正常
        private double attenValue = -9999; //衰减值

        /// <summary>
        /// 无参构造器
        /// </summary>
        public ATT_WG3020()
        {
            serialPort = new SerialPort(); //新建一个串口对象
            serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceived); //串口收到数据时
            #region 启动一个分析线程，该线程为死循环线程，通过一个信号量控制线程挂起与执行
            Thread analysisDataThread = new Thread(AnalysisReceiveData);
            analysisDataThread.IsBackground = true;
            analysisDataThread.Start();
            #endregion
            checkConnectionTimer.Elapsed += new System.Timers.ElapsedEventHandler(CheckConnect);
        }

        /// <summary>
        /// 型号名称WG3020(具体是不是这个型号不敢肯定，但协议文档名字就是这个型号)
        /// 该机型只能切换7个波长，分别为:1270,1310,1490,1550,1577,1625,1650
        /// </summary>
        public string Name => "WG3020";

        /// <summary>
        /// 连接参数类型
        /// </summary>
        public Type ParamType => typeof(SerialPortParam);

        /// <summary>
        /// 连接参数
        /// </summary>
        public object ConnectParam
        {
            get { return serialPortParam; }
            set
            {
                Type valueType = value.GetType();
                if (valueType.Equals(ParamType))
                {
                    serialPortParam = (SerialPortParam)value;
                }
            }
        }

        /// <summary>
        /// 是否连接成功
        /// </summary>
        public bool IsConnected => isConnected;

        /// <summary>
        /// 异常断开时，产生一个事件
        /// </summary>
        public event EventHandler BreakConnect;

        /// <summary>
        /// 调节衰减值
        /// </summary>
        /// <param name="atten">衰减值</param>
        /// <returns>是否调节成功</returns>
        public bool AdjustAtten(double atten)
        {
            if (!isConnected)
            {
                return false;
            }
            /* 调节衰减的命令 */
            byte[] headArr = { 0xaa, 0x02, 0x02, 0x01 }; //命令头
            //两个字节的功率值，16个位分别表示为：4位10dBm + 4位1dBm + 4位0.1dBm + 4位0.01dBm
            int d10 = (int)atten / 10;  //10位
            int d1 = (int)atten % 10; //个位
            int d01 = (int)atten * 10 % 10; //十分位
            int d001 = (int)atten * 100 % 10; //百分位
            byte heigh = (byte)(d10 << 4 | d1); //两个字节
            byte low = (byte)(d01 << 4 | d001);
            //拼接完整命令
            List<byte> orderBytesList = new List<byte>();
            orderBytesList.AddRange(headArr.AsEnumerable());
            orderBytesList.Add(heigh); //添加目标光功的高低位
            orderBytesList.Add(low);
            for (int i = 0; i < 10; i++) //命令固定16个字节，补10个字节的无效数据
            {
                orderBytesList.Add(0x00);
            }
            serialPort.Write(orderBytesList.ToArray(),0,orderBytesList.Count);
            bool setOk = setAttenEvent.WaitOne(1000); //1秒内未收到设置成功信号量，则认为设置失败
            return setOk;
        }

        /// <summary>
        /// 切换波长
        /// </summary>
        /// <param name="wavelength">波长</param>
        /// <returns>是否切换成功</returns>
        public bool ChangeWavelength(int wavelength)
        {
            if (!isConnected)
            {
                return false;
            }
            int waveIndex = wavelengthArr.ToList().IndexOf(wavelength);
            if (waveIndex == -1)
            {
                return false;
            }
            byte[] orderBytes = {0xaa,0x02,0x01,0x01,(byte)waveIndex,0x00,0x00,0x00,
            0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
            serialPort.Write(orderBytes, 0, orderBytes.Length);
            bool result = waveChangedEvent.WaitOne(1000); //1秒内收到信号量，认为切换波长成功，否则认为切换失败
            return result;
        }


        /// <summary>
        /// 获取当前衰减值
        /// </summary>
        /// <returns>衰减值</returns>
        public double GetAttenValue() {
            byte[] orderBytes = {0xaa, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
            serialPort.Write(orderBytes, 0, orderBytes.Length);
            bool got = getAttenValueEvent.WaitOne(1000); //1秒内未收到已经成功读取到衰减，则返回-9999
            if (!got)
            {
                return -9999;
            }
            return attenValue;
        }

        /// <summary>
        /// 连接光衰
        /// </summary>
        /// <returns>是否连接成功</returns>
        public bool Connect()
        {
            try
            {
                serialPort.PortName = serialPortParam.Portname;
                serialPort.BaudRate = serialPortParam.Baudrate;
                serialPort.Open();
                byte[] orderBytes = {0xaa, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
                serialPort.Write(orderBytes,0,orderBytes.Length);
                bool result = getMeterTypeEvent.WaitOne(1000); //1秒内收是否收到机器型号
                if (!result)
                {
                    return false;
                }
                checkConnectionTimer.Start(); //连接成功后启动定时器，检查连接是否正常
                isConnected = true;
                return true;
            }
            catch{
                return false;
            }
        }

        public void DisConnect()
        {
            try
            {
                checkConnectionTimer.Stop();
                serialPort.Close();
                isConnected = false;
            }
            catch
            {
                
            }
        }

        //数据到达时，释放解析的信号量
        private void DataReceived(object sender,SerialDataReceivedEventArgs args) {
            dataReceiveEvent.Set();
        }

        //分析收到的数据
        private void AnalysisReceiveData()
        {
            receiveByteList = new List<byte>();
            while (true)
            {
                dataReceiveEvent.WaitOne(); //线程会被挂起，直到收到信号量释放
                int datalength = 16; //一条命令16个字节
                int canReadCount = serialPort.BytesToRead; //可读取的字符串数量
                byte[] buff = new byte[canReadCount];
                receiveByteList.AddRange(buff.AsEnumerable()); //把读取到的字节数组追加到清单尾部
                while(receiveByteList.Count > 0 && receiveByteList[0] != 0xaa) //当不是0xaa开头时，移除第一个字节
                {
                    receiveByteList.RemoveAt(0);
                }
                if(receiveByteList.Count < datalength)  //数据不足时，不作分析，直接进入下一个循环
                {
                    continue;
                }
                /* aa 01开头是读取衰减值 */
                if (receiveByteList[0] == 0xaa && receiveByteList[1] == 0x01)
                {
                    byte high = receiveByteList[13];
                    byte low = receiveByteList[14];
                    attenValue = (high >> 4) * 10 + (high & 0x0f) + (low >> 4) * 0.1 + ((low & 0x0f) * 0.01);
                    getAttenValueEvent.Set();
                }
                else if (receiveByteList[0] == 0xaa && receiveByteList[1] == 0x02 && receiveByteList[2] == 0x02)
                { //aa 02开头是调节衰减器
                    setAttenEvent.Set();
                }
                else if (receiveByteList[0] == 0xaa && receiveByteList[1] == 0x30) //获取设备名称成功返回值
                {
                    getMeterTypeEvent.Set();
                }
                else if (receiveByteList[0] == 0xaa && receiveByteList[1] == 0x02 && receiveByteList[2] == 0x01) //调节波长成功
                {
                    waveChangedEvent.Set();
                }
            }
        }


        //定时检测串口是否正常打开，如果处于关闭状态产生一个事件
        private void CheckConnect(object sender,System.Timers.ElapsedEventArgs args)
        {
            if (!serialPort.IsOpen)
            {
                isConnected = false;
                BreakConnect?.Invoke(this, new EventArgs());
            }
        }
    }
}
